package Alibaba.AlibabaClient;

import java.io.*;
import java.net.*;
import org.apache.commons.cli.*;

public class ClientCLI {
	public class Status {

	}

	enum Action {
		BACKUP_FILE, RESTORE_FILE, BACKUP_DIR, RESTORE_DIR, LIST_FILES, CHECK_FILES, HELP, CREATE_SNAPSHOT, DELETE_SNAPSHOT, ERROR
	}

	protected static void printMainHelp() {
		System.out.println("Usage: alibaba command [options]");
		System.out.println("Commands:\n");
		System.out.println("Command name\t\tShort name\tDescription");
		System.out.println("--------------------------------------------------------------");
		System.out.println("backupdir\t\tbd\t\tBackup a directory");
		System.out.println("backupfile\t\tbf\t\tBackup a file");
		System.out.println("restoredir\t\trd\t\tRestore a directory");
		System.out.println("restorefile\t\trf\t\tRestore a file");
		System.out.println("list\t\t\tls\t\tList a directory");
		System.out.println("check\t\t\tch\t\tCheck and validate backup files");
		System.out.println("help\t\t\t?\t\tPrint usage information");
		System.out.println("createsnapshot\t\t\tcs\t\tCreate a snapshot for the user files");
		System.out.println("deletesnapshot\t\t\tds\t\tDelete a specified user files snapshot");

	}

	protected static int backupFileCmd(String[] args) throws Exception {
		CommandLineParser parser = new GnuParser();
		Options commandOptions = new Options();
		CommandLine commandLine;
		HelpFormatter formatter = new HelpFormatter();

		OptionBuilder.withDescription("The user name of the client");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("user_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("user"));

		OptionBuilder.withDescription("The name of the file");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("file_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("file"));

		try {
			commandLine = parser.parse(commandOptions, args);
		} catch (ParseException exp) {
			System.out.println(exp.getMessage());
			formatter.printHelp("backupfile", commandOptions);
			return -1;
		}

		String fileName = commandLine.getOptionValue("file");
		String userName = commandLine.getOptionValue("user");
		Service.backupFile(fileName, userName);
		return 1;
	}

	protected static int restoreFileCmd(String[] args) throws Exception {
		CommandLineParser parser = new GnuParser();
		Options commandOptions = new Options();
		CommandLine commandLine;
		HelpFormatter formatter = new HelpFormatter();

		OptionBuilder.withDescription("The user name of the client");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("user_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("user"));

		OptionBuilder.withDescription("The name of the file");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("file_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("file"));

		OptionBuilder.withDescription("The snapshot number");
		OptionBuilder.hasOptionalArg();
		OptionBuilder.withArgName("snapshot_number");
		commandOptions.addOption(OptionBuilder.create("snapshot"));

		try {
			commandLine = parser.parse(commandOptions, args);
		} catch (ParseException exp) {
			System.out.println(exp.getMessage());
			formatter.printHelp("backupfile", commandOptions);
			return -1;
		}

		String fileName = commandLine.getOptionValue("file");
		String userName = commandLine.getOptionValue("user");
		int snapshotNum = 0;
		try {
			snapshotNum = Integer.parseInt(commandLine.getOptionValue("snapshot") != null ? commandLine.getOptionValue("snapshot") : "0");
		} catch (NumberFormatException e) {
			System.out.println(e.getMessage());
			formatter.printHelp("restorefile", commandOptions);
			return -1;
		}

		Service.restoreFile(fileName, userName, snapshotNum);
		return 1;
	}

	protected static int backupDirCmd(String[] args) throws Exception {
		CommandLineParser parser = new GnuParser();
		Options commandOptions = new Options();
		CommandLine commandLine;
		HelpFormatter formatter = new HelpFormatter();

		OptionBuilder.withDescription("The user name of the client");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("user_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("user"));

		OptionBuilder.withDescription("The name of the directory");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("directory_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("dir"));

		try {
			commandLine = parser.parse(commandOptions, args);
		} catch (ParseException exp) {
			System.out.println(exp.getMessage());
			formatter.printHelp("backupdir", commandOptions);
			return -1;
		}

		String directoryName = commandLine.getOptionValue("dir");
		String userName = commandLine.getOptionValue("user");
		Service.backupDir(directoryName, userName);
		return 1;
	}

	protected static int restoreDirCmd(String[] args) throws Exception {
		CommandLineParser parser = new GnuParser();
		Options commandOptions = new Options();
		CommandLine commandLine;
		HelpFormatter formatter = new HelpFormatter();

		OptionBuilder.withDescription("The user name of the client");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("user_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("user"));

		OptionBuilder.withDescription("The name of the directory");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("directory_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("dir"));

		OptionBuilder.withDescription("The snapshot number");
		OptionBuilder.hasOptionalArg();
		OptionBuilder.withArgName("snapshot_number");
		commandOptions.addOption(OptionBuilder.create("snapshot"));

		try {
			commandLine = parser.parse(commandOptions, args);
		} catch (ParseException exp) {
			System.out.println(exp.getMessage());
			formatter.printHelp("backupdir", commandOptions);
			return -1;
		}

		String directoryName = commandLine.getOptionValue("dir");
		String userName = commandLine.getOptionValue("user");
		int snapshotNum = 0;
		try {
			snapshotNum = Integer.parseInt(commandLine.getOptionValue("snapshot") != null ? commandLine.getOptionValue("snapshot") : "0");
		} catch (NumberFormatException e) {
			System.out.println(e.getMessage());
			formatter.printHelp("restoredir", commandOptions);
			return -1;
		}

		Service.restoreDir(directoryName, userName, snapshotNum);
		return 1;
	}

	protected static int listFilesCmd(String[] args) throws Exception {
		CommandLineParser parser = new GnuParser();
		Options commandOptions = new Options();
		CommandLine commandLine;
		HelpFormatter formatter = new HelpFormatter();

		OptionBuilder.withDescription("The user name of the client");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("user_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("user"));

		OptionBuilder.withDescription("The name of the directory");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("directory_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("dir"));

		OptionBuilder.withDescription("The snapshot number");
		OptionBuilder.hasOptionalArg();
		OptionBuilder.withArgName("snapshot_number");
		commandOptions.addOption(OptionBuilder.create("snapshot"));

		try {
			commandLine = parser.parse(commandOptions, args);
		} catch (ParseException exp) {
			System.out.println(exp.getMessage());
			formatter.printHelp("backupdir", commandOptions);
			return -1;
		}

		String directoryName = commandLine.getOptionValue("dir");
		String userName = commandLine.getOptionValue("user");
		int snapshotNum = 0;
		try {
			snapshotNum = Integer.parseInt(commandLine.getOptionValue("snapshot") != null ? commandLine.getOptionValue("snapshot") : "0");
		} catch (NumberFormatException e) {
			System.out.println(e.getMessage());
			formatter.printHelp("listfiles", commandOptions);
			return -1;
		}

		Service.listFiles(directoryName, userName, snapshotNum);
		return 1;
	}

	protected static int checkFilesCmd(String[] args) throws Exception {
		CommandLineParser parser = new GnuParser();
		Options commandOptions = new Options();
		CommandLine commandLine;
		HelpFormatter formatter = new HelpFormatter();

		OptionBuilder.withDescription("The user name of the client");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("user_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("user"));

		OptionBuilder.withDescription("The name of the directory");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("directory_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("dir"));

		try {
			commandLine = parser.parse(commandOptions, args);
		} catch (ParseException exp) {
			System.out.println(exp.getMessage());
			formatter.printHelp("backupdir", commandOptions);
			return -1;
		}

		String directoryName = commandLine.getOptionValue("dir");
		String userName = commandLine.getOptionValue("user");
		Service.checkFiles(directoryName, userName);
		return 1;
	}

	protected static int createSnapshotCmd(String[] args) throws Exception {
		CommandLineParser parser = new GnuParser();
		Options commandOptions = new Options();
		CommandLine commandLine;
		HelpFormatter formatter = new HelpFormatter();

		OptionBuilder.withDescription("The user name of the client");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("user_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("user"));

		OptionBuilder.withDescription("The snapshot number");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("snapshot_number");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("snapshot"));

		try {
			commandLine = parser.parse(commandOptions, args);
		} catch (ParseException exp) {
			System.out.println(exp.getMessage());
			formatter.printHelp("backupdir", commandOptions);
			return -1;
		}

		String userName = commandLine.getOptionValue("user");
		int snapshotNum = 0;
		try {
			snapshotNum = Integer.parseInt(commandLine.getOptionValue("snapshot"));
		} catch (NumberFormatException e) {
			System.out.println(e.getMessage());
			formatter.printHelp("createsnapshot", commandOptions);
			return -1;
		}

		Service.createSnapshot(userName, snapshotNum);
		return 1;
	}

	protected static int deleteSnapshotCmd(String[] args) throws Exception {
		CommandLineParser parser = new GnuParser();
		Options commandOptions = new Options();
		CommandLine commandLine;
		HelpFormatter formatter = new HelpFormatter();

		OptionBuilder.withDescription("The user name of the client");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("user_name");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("user"));

		OptionBuilder.withDescription("The snapshot number");
		OptionBuilder.hasArg();
		OptionBuilder.withArgName("snapshot_number");
		OptionBuilder.isRequired();
		commandOptions.addOption(OptionBuilder.create("snapshot"));

		try {
			commandLine = parser.parse(commandOptions, args);
		} catch (ParseException exp) {
			System.out.println(exp.getMessage());
			formatter.printHelp("backupdir", commandOptions);
			return -1;
		}

		String userName = commandLine.getOptionValue("user");
		int snapshotNum = 0;
		try {
			snapshotNum = Integer.parseInt(commandLine.getOptionValue("snapshot"));
		} catch (NumberFormatException e) {
			System.out.println(e.getMessage());
			formatter.printHelp("deletesnapshot", commandOptions);
			return -1;
		}

		Service.deleteSnapshot(userName, snapshotNum);
		return 1;
	}

	protected static Action parseAction(String[] args) {
		String commandString = args[0];
		if (commandString.equals("backupfile") || commandString.equals("bf")) {
			return Action.BACKUP_FILE;
		} else if (commandString.equals("restorefile") || commandString.equals("rf")) {
			return Action.RESTORE_FILE;
		} else if (commandString.equals("backupdir") || commandString.equals("bd")) {
			return Action.BACKUP_DIR;
		} else if (commandString.equals("restoredir") || commandString.equals("rd")) {
			return Action.RESTORE_DIR;
		} else if (commandString.equals("list") || commandString.equals("ls")) {
			return Action.LIST_FILES;
		} else if (commandString.equals("check") || commandString.equals("ch")) {
			return Action.CHECK_FILES;
		} else if (commandString.equals("help") || commandString.equals("?")) {
			return Action.HELP;
		} else if (commandString.equals("createsnapshot") || commandString.equals("cs")) {
			return Action.CREATE_SNAPSHOT;
		} else if (commandString.equals("deletesnapshot") || commandString.equals("ds")) {
			return Action.DELETE_SNAPSHOT;
		} else {
			return Action.ERROR;
		}
	}

	private static void doCommand(String[] args) throws Exception {

		Action action = parseAction(args);
		if (action == Action.ERROR) {
			System.out.println("Input error. Type 'help' for usage");
			return;
		}
		String[] cmdArgs = new String[args.length - 1];
		System.arraycopy(args, 1, cmdArgs, 0, args.length - 1);

		switch (action) {

		case BACKUP_FILE:
			backupFileCmd(cmdArgs);
			break;

		case RESTORE_FILE:
			restoreFileCmd(cmdArgs);
			break;

		case BACKUP_DIR:
			backupDirCmd(cmdArgs);
			break;

		case RESTORE_DIR:
			restoreDirCmd(cmdArgs);
			break;

		case LIST_FILES:
			listFilesCmd(cmdArgs);
			break;

		case CHECK_FILES:
			checkFilesCmd(cmdArgs);
			break;

		case HELP:
			printMainHelp();
			break;

		case CREATE_SNAPSHOT:
			createSnapshotCmd(cmdArgs);
			break;

		case DELETE_SNAPSHOT:
			deleteSnapshotCmd(cmdArgs);
			break;

		default:
			System.out.println("Not implememented yet.");
		}
	}

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		if (args.length == 0) {
			System.out.println("Type 'alibaba help' for usage");
			System.exit(-1);
		}
		try {
			doCommand(args);
		} catch (MalformedURLException e) {
			e.printStackTrace();
			System.out.println("An exception occurred while processing the command. The results are inpredictable.");
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("An exception occurred while processing the command. The results are inpredictable.");
		}
		return;
	}
}
